/*
 *  copy source from lua-5.1.4 to learn lua implementation
 */
#ifndef lobject_h
#define lobject_h

#include <stdarg.h>

#include "llimits.h"

#define LAST_TAG  LUA_TTHREAD

#define NUM_TAGS  (LAST_TAG+1)

typedef union GCObject GCObject;

typedef union {
  GCObject *gc;
  void *p;
  lua_Number n;
  int b;
} Value;

#define TValuefields	Value value; int tt

typedef struct lua_TValue {
  TValuefields;
} TValue;

#define lmod(s,size) \
	(check_exp((size&(size-1))==0, (cast(int, (s) & ((size)-1)))))

#define ttype(o)	((o)->tt)
#define nvalue(o) check_exp(ttisnumber(o), (o)->value.n)
#define clvalue(o)  check_exp(ttisfunction(o), &(o)->value.gc->cl)
#define rawtsvalue(o) check_exp(ttisstring(o), &(o)->value.gc->ts)
#define tsvalue(o) (&rawtsvalue(o)->tsv)

#define ttisnil(o)	(ttype(o) == LUA_TNIL)
#define ttisnumber(o)	(ttype(o) == LUA_TNUMBER)
#define ttisstring(o)	(ttype(o) == LUA_TSTRING)
#define ttistable(o)	(ttype(o) == LUA_TTABLE)
#define ttisfunction(o)	(ttype(o) == LUA_TFUNCTION)
#define ttisboolean(o)	(ttype(o) == LUA_TBOOLEAN)
#define ttisuserdata(o)	(ttype(o) == LUA_TUSERDATA)
#define ttisthread(o)	(ttype(o) == LUA_TTHREAD)
#define ttislightuserdata(o)	(ttype(o) == LUA_TLIGHTUSERDATA)

#define CommonHeader  GCObject *next; lu_byte tt; lu_byte marked

typedef struct GCheader {
    CommonHeader;
} GCheader;

typedef TValue *StkId;  /* index to stack elements */

typedef union TString {
  L_Umaxalign dummy;
  struct {
    CommonHeader;
    lu_byte reserved;
    unsigned int hash;
    size_t len;
  } tsv;
} TString;

typedef union TKey {
  struct {
    TValuefields;
    struct Node *next;
  } nk;
  TValue tvk;
} TKey;

typedef struct Node {
  TValue i_val;
  TKey i_key;
} Node;

typedef struct Table {
  CommonHeader;
  lu_byte flags;
  lu_byte lsizenode;
  struct Table *metatable;
  TValue *array;
  Node *node;
  Node *lastfree;
  GCObject *gclist;
  int sizearray;
} Table;

typedef struct Proto {
  CommonHeader;
  TValue *k;
  Instruction *code;
  struct Proto **p;
  int *lineinfo;
  struct LocVar *locvars;
  TString **upvalues;
  TString *source;
  int sizeupvalues;
  int sizek;
  int sizecode;
  int sizelineinfo;
  int sizep;  /* size of `p' */
  int sizelocvars;
  int linedefined;
  int lastlinedefined;
  GCObject *gclist;
  lu_byte nups;  /* number of upvalues */
  lu_byte numparams;
  lu_byte is_vararg;
  lu_byte maxstacksize;
} Proto;

typedef struct UpVal {
  CommonHeader;
  TValue *v;  /* points to stack or to its own value */
  union {
    TValue value;  /* the value (when closed) */
    struct {  /* double linked list (when open) */
      struct UpVal *prev;
      struct UpVal *next;
    } l;
  } u;
} UpVal;

#define ClosureHeader \
	CommonHeader; lu_byte isC; lu_byte nupvalues; GCObject *gclist; \
	struct Table *env

typedef struct CClosure {
  ClosureHeader;
  lua_CFunction f;
  TValue upvalue[1];
} CClosure;

typedef struct LClosure {
  ClosureHeader;
  struct Proto *p;
  UpVal *upvals[1];
} LClosure;

typedef union Closure {
  CClosure c;
  LClosure l;
} Closure;

#define getstr(ts)  cast(const char*, (ts) + 1)
#define svalue(o)   getstr(rawtsvalue(o))

typedef union Udata {
  L_Umaxalign dummy;  /* ensures maximum alignment for `local' udata */
  struct {
    CommonHeader;
    struct Table *metatable;
    struct Table *env;
    size_t len;
  } uv;
} Udata;

#define checkconsistency(obj) \
  lua_assert(!iscollectable(obj)  || (ttype(obj) == (obj)->value.gc->gch.tt))

#define checkliveness(g, obj) \
  lua_assert(!iscollectable(obj) || \
  ((ttype(obj) == (obj)->value.gc->gch.tt) && !isdead(g, (obj)->value.gc)))

#define setobj(L,obj1,obj2) \
  { const TValue *o2=(obj2); TValue *o1=(obj1); \
    o1->value = o2->value; o1->tt=o2->tt; \
    checkliveness(G(L),o1); }

#define setnilvalue(obj)  ((obj)->tt = LUA_TNIL)

#define sethvalue(L, obj, x)                                      \
  { TValue *i_o = (obj);                                          \
    i_o->value.gc = cast(GCObject *, (x)); i_o->tt = LUA_TTABLE;  \
    checkliveness(G(L), i_o); }

#define setsvalue(L, obj, x)                                      \
  { TValue *i_o=(obj);                                            \
    i_o->value.gc = cast(GCObject *, (x)); i_o->tt->LUA_TSTRING;  \
    checkliveness(G(L), i_o); }

#define iscollectable(o)	(ttype(o) >= LUA_TSTRING)    

LUAI_DATA const TValue luaO_nilobject_;
#define luaO_nilobject    (&luaO_nilobject_)

#endif
